package com.jaws.core.mvc.exception;

import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;

import com.google.common.collect.Lists;
import com.jaws.core.common.log.Log;
import com.jaws.core.common.log.LogOp;
import com.jaws.core.common.util.WebJsonUtil;

/**
 * 通用异常处理基类
 * 
 * @author maojian
 * @date 2017-05-12 09:53:55
 * @since v1.0.0
 */
public abstract class AbstractCommonHandlerExceptionResolver extends AbstractHandlerExceptionResolver {

	protected static final String UTF8_ENC = "UTF-8";

	protected static final Charset UTF8 = Charset.forName(UTF8_ENC);

	/**
	 * 是否RESTful服务，是的话，默认认为所有请求都是JSON请求
	 */
	protected boolean restService;

	@Resource
	private ApplicationContext context;

	/**
	 * (non-Javadoc)
	 */
	@Override
	protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		if (!support(request, response, handler, ex)) {
			return null;
		}
		recordException(ex, request);
		notifyModule(request, response, handler, ex);
		boolean isJsonRequest = false;
		if (restService) {
			isJsonRequest = true;
		} else {
			isJsonRequest = WebJsonUtil.isJsonRequest(request, handler);
		}
		if (isJsonRequest) {
			return resolveExceptionForJson(request, response, handler, ex);
		}
		return resolveExceptionForNonJson(request, response, handler, ex);
	}

	/**
	 * 通知业务模块
	 * 
	 * @author maojian
	 * @date 2017-12-05 17:09:14
	 * @since v1.0.0
	 * @param request
	 * @param response
	 * @param handler
	 * @param ex
	 */
	private void notifyModule(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		Map<String, ExceptionNotify> nofityMap = context.getBeansOfType(ExceptionNotify.class);
		List<ExceptionNotify> notifys = Lists.newArrayList(nofityMap.values());
		for (ExceptionNotify notify : notifys) {
			try {
				notify.notifyException(request, response, handler, ex);
			} catch (Exception e) {
				logger.error(Log.op(LogOp.EXP_NOTIFY_FAIL).msg("resolveExceptionForNonJson Fail").toString(), e);
			}
		}
	}

	/**
	 * 异常处理器是否支持当前异常
	 * 
	 * @param request
	 *        HTTP请求
	 * @param response
	 *        HTTP响应
	 * @param handler
	 *        请求处理器
	 * @param ex
	 *        异常对象
	 * @return 支持则返回<code>TRUE</code>
	 */
	protected abstract boolean support(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

	/**
	 * 记录异常信息
	 * 
	 * @param ex
	 * @param request
	 */
	protected abstract void recordException(Exception ex, HttpServletRequest request);

	/**
	 * 解析Json请求的异常
	 * 
	 * @param request
	 *        HTTP请求
	 * @param response
	 *        HTTP响应
	 * @param handler
	 *        请求处理器
	 * @param ex
	 *        异常对象
	 * @return 视图对象
	 */
	protected abstract ModelAndView resolveExceptionForJson(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

	/**
	 * 处理非Json请求异常
	 * 
	 * @param request
	 *        HTTP请求
	 * @param response
	 *        HTTP响应
	 * @param handler
	 *        请求处理器
	 * @param ex
	 *        异常对象
	 * @return 视图对象
	 */
	protected abstract ModelAndView resolveExceptionForNonJson(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

	/**
	 * @param restService
	 *        the restService to set
	 */
	public void setRestService(boolean restService) {
		this.restService = restService;
	}

}
